home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
050
/
madtrb13.arc
/
EXEC3.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1986-01-18
|
13KB
|
321 lines
{ EXEC.PAS version 1.5
Copyright (C) 1986 by Bela Lubkin (1/14/86)
Noncommercial use only EXCEPT with permission from Bela Lubkin; send
EasyPlex to ID 76703,3015 for permission.
See "VERY IMPORTANT NOTES" below before using these functions.
REQUIRES Turbo Pascal version 3.0 (may work with later versions, when they
appear)
Allows you to
o Call MS-DOS programs
o Get the return codes from those programs
o Get strings from the MS-DOS environment
Calling information
-------------------
Function SubProcess(CommandLine: _Exec_Str255): Integer;
Calls an executable image (.COM or .EXE file) using MS-DOS function
4Bh, Exec. The parameter CommandLine must contain both the name of the
program to run and the arguments to be passed to it, seperated by a
space. Path searching and other amenities are not performed; the passed
in name must be specific enough to allow the file to be found, i.e.
'CHKDSK' will NOT work. At least 'CHKDSK.COM' must be specified, and a
drive and path name will help even more. For example,
'C:\SYSTEM\CHKDSK.COM'
'A:\WS.COM DOCUMENT.1'
'C:\DOS\LINK.EXE TEST;'
'D:\ASSEM\MASM.EXE PROG1 PROG1.OBJ NUL PROG1.MAP'
'C:\COMMAND.COM /C COPY *.* B:\BACKUP >FILESCOP.IED'
The last example uses COMMAND.COM to invoke a DOS internal command and
to perform redirection. Only with the use of COMMAND.COM can the
following be done: redirection; piping; path searching; searching for
the extension of a program (.COM, .EXE, or .BAT); batch files; and
internal DOS commands.
Because the COMMAND-assisted Exec function is so useful, a seperate
function, SubProcessViaCOMMAND, is provided for that purpose.
The integer return value of SubProcess is the error value returned by
DOS on completion of the Exec call. If it is nonzero, the call failed.
Here is a list of likely error values:
0: Success
2: File/path not found
3: Path not found
4: Too many files open (no handles left)
5: Access denied
8: Not enough memory to load program
10: Illegal environment (greater than 32K)
11: Illegal .EXE file format
32: Sharing violation
33: Lock violation
If you get any other result, consult an MS-DOS Technical Reference
manual.
Function GetEnvStr(SearchString: _Exec_Str255): _Exec_Str255;
Gets a string from the MS-DOS environment. The parameter SearchString
specifies the desired environment string. The function result returns
the value of that string from the environment. If the string is not
found, a null string is returned. SearchString may have one special
value, '='. This returns garbage under MS-DOS 2.x. Under MS-DOS 3.x,
it returns the pathname under which the currently running program was
invoked. Examples:
GetEnvStr('COMSPEC') might = 'C:\COMMAND.COM'
GetEnvStr('PROMPT') might = '$p $g'
GetEnvStr('REFLEX') might = 'Herc'
GetEnvStr('=') might = 'C:\TURBO\exectest.COM'
Only an exact match will succeed; case IS significant. Do not include
an equal sign in the search string (GetEnvStr('COMSPEC=') will fail).
Note: if you are wondering why there is no SetEnvStr procedure, read
an MS-DOS Technical Reference manual.
Function GetComSpec: _Exec_Str66;
This is a special case of GetEnvStr and simply returns the COMSPEC
environment string. It is included for compatability with previous
EXEC.PAS versions.
Function SubProcessViaCOMMAND(CommandLine: _Exec_Str255): Integer;
This is a special case of SubProcess. The CommandLine is passed to
COMMAND.COM, which does all further processing. Command lines invoked
via this procedure can do redirection and piping; undergo the normal DOS
PATH search; may be batch files; and may be internal DOS commands such
as COPY and RENAME.
Disadvantages of this approach are: a copy of COMMAND.COM must be
present (not always true on a floppy-based system); a slight time and
memory penalty is involved due to the loading of an extra copy of
COMMAND.COM (about 3K under DOS 3.1); the subprocess return code
(Errorlevel) is lost. In most cases the benefits will outweight the
disadvantages.
The integer return code is the same as for SubProcess.
Note: you may be wondering why there is not
Function Shell: Integer;
This is a special case of SubProcess. It gives a DOS prompt to the
user. Typing EXIT returns to the Turbo program. The integer return
code is the same as for SubProcess.
Function SubProcessReturnCode: Integer;
This function calls MS-DOS function 4Dh, Get Return Code of a
Sub-process. The integer return value is the return code set by the
last subprocess you called. Like Turbo's IOResult, SubProcessReturnCode
is only valid once after a SubProcess call, reverting to 0 on successive
calls. The return code obtained after using SubProcessViaCOMMAND or
Shell is the code returned by COMMAND.COM, not by any other program, and
is not likely to be useful.
Note: Turbo programs can set the return code by using the Halt
procedure with a parameter, e.g. Halt(20);. Other languages can call
DOS function 4Ch (Terminate) with the return code in AL.
VERY IMPORTANT NOTES
--------------------
The Exec calls (SubProcess, SubProcessViaCOMMAND, Shell) will not work
unless you restrict Turbo's heap. To do this, lower "mAximum dynamic free
memory" on the compiler Options menu to a reasonable value. What is
reasonable depends on your program's use of the heap and the stack, and must
be determined by you. If you use neither the heap nor recursion, as low as
400h (16K bytes) is probably more than enough.
The Exec calls CANNOT be called from within the interactive Turbo compiler
system. They can only be called from .COM or .CHN files running outside of
the Turbo environment.
Revision history
----------------
Version 1.5 1/14/86 fixes the memory freeing bug by removing support for
Turbo 2.0. String types changed to minimize chances of
collision. General environment support added. Explicit calls
for Exec-via-COMMAND.COM and Exec-to-DOS-prompt added. Support
for getting the subprocess return code added. Major
documentation overhaul. NOW REQUIRES TURBO 3.0!
(Thanks to Stu Fuller 76703,501 for pointing out how easy it
was to add full environment support).
Version 1.4 attempts to fix a bug in the freeing of memory before the
Exec call.
Version 1.3 works with MS-DOS 2.0 and up, TURBO PASCAL version 1.0 and up.
Version 1.2 had a subtle but dangerous bug: I set a variable that was
addressed relative to BP, using a destroyed BP!
Version 1.1 didn't work with Turbo 2.0 because I used Turbo 3.0 features
Version 1.0 only worked with DOS 3.0 due to a subtle bug in DOS 2.x
- Bela Lubkin
CompuServe 76703,3015
}
Type
_Exec_Str66=String[66];
_Exec_Str255=String[255];
Function SubProcess(CommandLine: _Exec_Str255): Integer;
Const
SSSave: Integer=0;
SPSave: Integer=0;
Var
Regs: Record Case Integer Of
1: (AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags: Integer);
2: (AL,AH,BL,BH,CL,CH,DL,DH: Byte);
End;
FCB1,FCB2: Array [0..36] Of Byte;
PathName: _Exec_Str66;
CommandTail: _Exec_Str255;
ParmTable: Record
EnvSeg: Integer;
ComLin: ^Integer;
FCB1Pr: ^Integer;
FCB2Pr: ^Integer;
End;
RegsFlags: Integer;
Begin
If Pos(' ',CommandLine)=0 Then
Begin
PathName:=CommandLine+#0;
CommandTail:=^M;
End
Else
Begin
PathName:=Copy(CommandLine,1,Pred(Pos(' ',CommandLine)))+#0;
CommandTail:=Copy(CommandLine,Pos(' ',CommandLine),255)+^M;
End;
CommandTail[0]:=Pred(CommandTail[0]);
With Regs Do
Begin
FillChar(FCB1,Sizeof(FCB1),0);
AX:=$2901;
DS:=Seg(CommandTail[1]);
SI:=Ofs(CommandTail[1]);
ES:=Seg(FCB1);
DI:=Ofs(FCB1);
MsDos(Regs); { Create FCB 1 }
FillChar(FCB2,Sizeof(FCB2),0);
AX:=$2901;
ES:=Seg(FCB2);
DI:=Ofs(FCB2);
MsDos(Regs); { Create FCB 2 }
With ParmTable Do
Begin
EnvSeg:=MemW[CSeg:$002C];
ComLin:=Addr(CommandTail);
FCB1Pr:=Addr(FCB1);
FCB2Pr:=Addr(FCB2);
End;
InLine($8D/$96/ PathName /$42/ { <DX>:=Ofs(PathName[1]); }
$8D/$9E/ ParmTable / { <BX>:=Ofs(ParmTable); }
$B8/$00/$4B/ { <AX>:=$4B00; }
$1E/$55/ { Save <DS>, <BP> }
$16/$1F/ { <DS>:=Seg(PathName[1]); }
$16/$07/ { <ES>:=Seg(ParmTable); }
$2E/$8C/$16/ SSSave / { Save <SS> in SSSave }
$2E/$89/$26/ SPSave / { Save <SP> in SPSave }
$FA/ { Disable interrupts }
$CD/$21/ { Call MS-DOS }
$FA/ { Disable interrupts }
$2E/$8B/$26/ SPSave / { Restore <SP> }
$2E/$8E/$16/ SSSave / { Restore <SS> }
$FB/ { Enable interrupts }
$5D/$1F/ { Restore <BP>,<DS> }
$9C/$8F/$86/ RegsFlags / { Flags:=<CPU flags> }
$89/$86/ Regs ); { Regs.AX:=<AX>; }
{ The messing around with SS and SP is necessary because under DOS 2.x,
after returning from an EXEC call, ALL registers are destroyed except
CS and IP! I wish I'd known that before I released this package the
first time... }
If (RegsFlags And 1)<>0 Then SubProcess:=AX
Else SubProcess:=0;
End;
End;
Function GetEnvStr(SearchString: _Exec_Str255): _Exec_Str255;
Type
Env=Array [0..32767] Of Char;
Var
EPtr: ^Env;
EStr: _Exec_Str255;
Done: Boolean;
I: Integer;
Begin
GetEnvStr:='';
If SearchString<>'' Then
Begin
EPtr:=Ptr(MemW[CSeg:$002C],0);
I:=0;
SearchString:=SearchString+'=';
Done:=False;
EStr:='';
Repeat
If EPtr^[I]=#0 Then
Begin
If EPtr^[Succ(I)]=#0 Then
Begin
Done:=True;
If SearchString='==' Then
Begin
EStr:='';
I:=I+4;
While EPtr^[I]<>#0 Do
Begin
EStr:=EStr+EPtr^[I];
I:=Succ(I);
End;
GetEnvStr:=EStr;
End;
End;
If Copy(EStr,1,Length(SearchString))=SearchString Then
Begin
GetEnvStr:=Copy(EStr,Succ(Length(SearchString)),255);
Done:=True;
End;
EStr:='';
End
Else EStr:=EStr+EPtr^[I];
I:=Succ(I);
Until Done;
End;
End;
Function GetComSpec: _Exec_Str66;
Begin
GetComSpec:=GetEnvStr('COMSPEC');
End;
Function SubProcessViaCOMMAND(CommandLine: _Exec_Str255): Integer;
Begin
SubProcessViaCOMMAND:=SubProcess(GetComSpec+' /C '+CommandLine);
End;
Function SubProcessReturnCode: Integer;
Var
Regs: Record Case Integer Of
1: (AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags: Integer);
2: (AL,AH,BL,BH,CL,CH,DL,DH: Byte);
End;
Begin
Regs.AH:=$4D;
MsDos(Regs);
SubProcessReturnCode:=Regs.AX;
End;
{ Example program. Set both mInimum and mAximum free dynamic memory to 100
and compile this to a .COM file. Delete the next line to enable: }
(*
Var Command: _Exec_Str255;
I: Integer;
Begin
WriteLn('Enter a * to quit; put a * before a command to use COMMAND.COM.');
Repeat
Write('=->');
ReadLn(Command);
If Command='*' Then Halt;
If Command<>'' Then
Begin
If Command[1]='*' Then
I:=SubProcessViaCOMMAND(Copy(Command,2,255))
Else I:=SubProcess(Command);
If I<>0 Then WriteLn('Error - ',I);
WriteLn('Return code = ',SubProcessReturnCode);
End;
Until False;
End.
*)